package org.linlinjava.litemall.db.service;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.linlinjava.litemall.db.dao.LitemallQuoteCommodityMapper;
import org.linlinjava.litemall.db.dao.LitemallQuoteLayoutMapper;
import org.linlinjava.litemall.db.domain.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

@Service
public class LitemallQuoteService {
    @Resource
    LitemallQuoteCommodityMapper quoteCommodityMapper;
    @Resource
    LitemallQuoteLayoutMapper quoteLayoutMapper;
    @Autowired
    LitemallCommodityService commodityService;

    public void addLayout(LitemallQuoteLayout layout) throws Exception{
        LitemallQuoteLayoutExample example = new LitemallQuoteLayoutExample();
        example.or().andPidEqualTo(layout.getPid());
        List<LitemallQuoteLayout> list = quoteLayoutMapper.selectByExample(example);
        for (LitemallQuoteLayout l : list) {
            if (l.getQuoteName().equals(layout.getQuoteName())) {
                throw new Exception("已有同名节点，请勿重复添加");
            }
        }
        quoteLayoutMapper.insertSelective(layout);
    }

    public List<LitemallQuoteLayout> findLayoutByBrand(Integer brandId) {
        LitemallQuoteLayoutExample example = new LitemallQuoteLayoutExample();
        example.or().andBrandIdEqualTo(brandId).andPidEqualTo(0);
        return quoteLayoutMapper.selectByExample(example);
    }

    public LitemallQuoteLayout findLayout(Integer id) {
        return quoteLayoutMapper.selectByPrimaryKey(id);
    }

    public LitemallQuoteLayout findLayout(String name, Integer brandId, Integer pid) {
        LitemallQuoteLayoutExample example = new LitemallQuoteLayoutExample();
        example.or().andQuoteNameEqualTo(name).andBrandIdEqualTo(brandId).andPidEqualTo(pid);
        return quoteLayoutMapper.selectOneByExample(example);
    }

    public Map<String, Object> findByPid(Integer id, Integer brandId) {
        Map<String, Object> result = new LinkedHashMap<>();
        {
            LitemallQuoteLayoutExample example = new LitemallQuoteLayoutExample();
            example.or().andPidEqualTo(id).andBrandIdEqualTo(brandId);
            result.put("childLayout", quoteLayoutMapper.selectByExample(example));
        }
        {
            LitemallQuoteCommodityExample example = new LitemallQuoteCommodityExample();
            example.or().andPidEqualTo(id);
            List<LitemallQuoteCommodity> temp = quoteCommodityMapper.selectByExample(example);
            if (temp != null && temp.size() > 0) {
                for (LitemallQuoteCommodity commodity : temp) {
                    commodity.setDetailInfo(commodityService.selectByIdSimple(commodity.getCommodityId()));
                }
                result.put("childCommodity", temp);
            }
        }
        return result;
    }

    public void findByParent(LitemallQuoteLayout parent) {
        {
            LitemallQuoteLayoutExample example = new LitemallQuoteLayoutExample();
            example.or().andPidEqualTo(parent.getId());
            parent.setChildLayout(quoteLayoutMapper.selectByExample(example));
        }
        {
            LitemallQuoteCommodityExample example = new LitemallQuoteCommodityExample();
            example.or().andPidEqualTo(parent.getId());
            List<LitemallQuoteCommodity> temp = quoteCommodityMapper.selectByExample(example);
            if (temp != null && temp.size() > 0) {
                for (LitemallQuoteCommodity commodity : temp) {
                    commodity.setDetailInfo(commodityService.selectByIdSimple(commodity.getCommodityId()));
                }
            }
            parent.setChildCommodity(temp);
        }
    }

    public List<LitemallQuoteLayout> getAllByBrand(Integer brandId) {
        LitemallQuoteLayoutExample layoutExample = new LitemallQuoteLayoutExample();
        layoutExample.or().andBrandIdEqualTo(brandId);
        List<LitemallQuoteLayout> tempList = quoteLayoutMapper.selectByExample(layoutExample);
        if (tempList == null || tempList.size() < 1) {
            return null;
        }
        cleanLoop(tempList);
        List<Integer> parentIdList = new LinkedList<>();
        Map<Integer, List<LitemallQuoteLayout>> sortedLayout = new LinkedHashMap<>();
        for (LitemallQuoteLayout layout : tempList) {
            Integer pid = layout.getPid();
            List<LitemallQuoteLayout> temp = sortedLayout.containsKey(pid) ? sortedLayout.get(pid) : new LinkedList<>();
            temp.add(layout);
            sortedLayout.put(pid, temp);
            parentIdList.add(layout.getId());
        }
        LitemallQuoteCommodityExample commodityExample = new LitemallQuoteCommodityExample();
        commodityExample.or().andPidIn(parentIdList);
        List<LitemallQuoteCommodity> tempCommodity = quoteCommodityMapper.selectByExample(commodityExample);
        Map<Integer, List<LitemallQuoteCommodity>> sortedCommodity = new LinkedHashMap<>();
//        List<LitemallCommodity> commodityList = commodityService.selectByCondition(1, Integer.MAX_VALUE, null, null, Collections.singletonList(brandId), null, null).getList();
//        Map<Integer, LitemallCommodity> commodityMap = new LinkedHashMap<>();
//        for (LitemallCommodity commodity : commodityList) {
//            commodityMap.put(commodity.getId(), commodity);
//        }
        for (LitemallQuoteCommodity commodity : tempCommodity) {
            Integer pid = commodity.getPid();
//            commodity.setDetailInfo(commodityMap.get(commodity.getCommodityId()));
            List<LitemallQuoteCommodity> list = sortedCommodity.containsKey(pid) ? sortedCommodity.get(pid) : new LinkedList<>();
            list.add(commodity);
            sortedCommodity.put(pid, list);
        }
        for (LitemallQuoteLayout layout : tempList) {
            layout.setChildCommodity(sortedCommodity.get(layout.getId()));
            layout.setChildLayout(sortedLayout.get(layout.getId()));
        }
        tempList.removeIf(layout -> layout.getPid() != 0);
        return tempList;
    }

    public void cleanLoop(List<LitemallQuoteLayout> tempList) {
        Map<Integer, LitemallQuoteLayout> idMap = new LinkedHashMap<>();
        List<Integer> okList = new LinkedList<>();
        List<Integer> badList = new LinkedList<>();

        for (LitemallQuoteLayout layout : tempList) {
            idMap.put(layout.getId(), layout);
        }
        for (LitemallQuoteLayout layout : tempList) {
            checkLoop(layout, idMap, okList, badList, null);
        }
        if (badList.size() > 0) {
            LitemallQuoteLayoutExample example = new LitemallQuoteLayoutExample();
            example.or().andIdIn(badList);
            quoteLayoutMapper.deleteByExample(example);
        }
    }

    public boolean checkLoop(LitemallQuoteLayout layout) {
        Map<Integer, LitemallQuoteLayout> map = new LinkedHashMap<>();
        LitemallQuoteLayoutExample layoutExample = new LitemallQuoteLayoutExample();
        layoutExample.or().andBrandIdEqualTo(layout.getBrandId());
        List<LitemallQuoteLayout> tempList = quoteLayoutMapper.selectByExample(layoutExample);
        for (LitemallQuoteLayout l : tempList) {
            map.put(l.getId(), l);
        }
        map.put(layout.getId(), layout);
        return checkLoop(layout, map, null);
    }

    private boolean checkLoop(LitemallQuoteLayout layout, Map<Integer, LitemallQuoteLayout> idMap, List<Integer> idList) {
        if (idList == null) {
            idList = new LinkedList<>();
        }
        if (layout == null) {
            return false;
        }
        int id = layout.getId();
        int pid = layout.getPid();
        if (pid == 0) {
            return true;
        }
        if (pid == id || idList.contains(pid)) {
            return false;
        }
        idList.add(id);
        return checkLoop(idMap.get(pid), idMap, idList);
    }

    private void checkLoop(LitemallQuoteLayout layout, Map<Integer, LitemallQuoteLayout> idMap, List<Integer> okList, List<Integer> badList, List<Integer> tempList) {
        if (tempList == null) {
            tempList = new LinkedList<>();
        }
        if (layout == null) {
            badList.addAll(tempList);
            tempList.clear();
            return;
        }
        int id = layout.getId();
        if (okList.contains(id)) {
            return;
        }
        int pid = layout.getPid();
        if (pid == 0 || okList.contains(pid)) {
            okList.add(id);
            okList.addAll(tempList);
            tempList.clear();
            return;
        }
        if (pid == id || badList.contains(pid) || tempList.contains(pid)) {
            badList.add(id);
            badList.addAll(tempList);
            tempList.clear();
            return;
        }
        tempList.add(id);
        checkLoop(idMap.get(pid), idMap, okList, badList, tempList);
    }

    public void updateByPrimaryKey(LitemallQuoteLayout layout) throws Exception{
        LitemallQuoteLayoutExample example = new LitemallQuoteLayoutExample();
        example.or().andPidEqualTo(layout.getPid());
        List<LitemallQuoteLayout> list = quoteLayoutMapper.selectByExample(example);
        for (LitemallQuoteLayout l : list) {
            if (l.getQuoteName().equals(layout.getQuoteName())) {
                throw new Exception("本层已有重名节点，请勿重复添加");
            }
        }
        quoteLayoutMapper.updateByPrimaryKeySelective(layout);
    }

    public void delete(LitemallQuoteLayout layout) {
        LitemallQuoteLayoutExample example = new LitemallQuoteLayoutExample();
        example.or().andIdEqualTo(layout.getId()).andBrandIdEqualTo(layout.getBrandId());
        quoteLayoutMapper.deleteByExample(example);
    }

    public void addCommodity(LitemallQuoteCommodity cmd) {
        quoteCommodityMapper.insertSelective(cmd);
    }

    public LitemallQuoteCommodity findCommodity(Integer id) {
        return quoteCommodityMapper.selectByPrimaryKey(id);
    }

    public void updateCommodity(LitemallQuoteCommodity cmd) {
        quoteCommodityMapper.updateByPrimaryKeySelective(cmd);
    }

    public void deleteCommodity(Integer id) {
        quoteCommodityMapper.deleteByPrimaryKey(id);
    }

    public String updateByXml(Integer brandId, Sheet sheet) {
        Map<String, LitemallQuoteLayout> dictionary = new LinkedHashMap<>();
        List<LitemallCommodity> tempList = commodityService.selectByCondition(1, Integer.MAX_VALUE, null, null, Collections.singletonList(brandId), null, null).getList();
        List<Integer> legalIdList = new LinkedList<>();
        StringBuilder msg = new StringBuilder();
        for (LitemallCommodity commodity : tempList) {
            legalIdList.add(commodity.getId());
        }
        for (Row row : sheet) {
            if (row.getRowNum() == 0) {
                continue;
            }
            int pid = 0;
            for (Cell cell : row) {
                try {
                    String content = cell.getStringCellValue();
                    if (StringUtils.isEmpty(content)) {
                        continue;
                    }
                    int index = cell.getColumnIndex();
                    if (index < 5) {
                        if (!dictionary.containsKey(content + pid)) {
                            LitemallQuoteLayout layout = findLayout(content, brandId, pid);
                            if (layout == null) {
                                LitemallQuoteLayout temp = new LitemallQuoteLayout();
                                temp.setBrandId(brandId);
                                temp.setQuoteName(content);
                                temp.setPid(pid);
                                addLayout(temp);
                                dictionary.put(content + pid, temp);
                                pid = temp.getId();
                            } else {
                                dictionary.put(content + pid, layout);
                                pid = layout.getId();
                            }
                        } else {
                            LitemallQuoteLayout layout = dictionary.get(content + pid);
                            pid = layout.getId();
                        }
                    } else if (index == 5) {
                        String[] commodityString = content.split(";");
                        addCommodity(commodityString, legalIdList, pid);
                    }
                } catch (Exception e) {
                    msg.append("error occurred：").append(e.getMessage()).append(" at row ").append(cell.getRowIndex()).append(" and column ").append(cell.getColumnIndex());
                }
            }
        }
        msg.append(msg.length() == 0 ? "insert successful" : "\n Please Check the XML");
        return msg.toString();
    }

    private void addCommodity(String[] commodityString, List<Integer> legalIdList, int pid) throws Exception {
        for (String string : commodityString) {
            if (StringUtils.isEmpty(string)) {
                continue;
            }
            String[] info = string.split(",");
            if (info.length != 2) {
                throw new Exception("Error");
            }
            Integer commodityId = Integer.parseInt(info[0]);
            BigDecimal price = new BigDecimal(info[1]);
            if (!legalIdList.contains(commodityId)) {
                throw new Exception("Wrong Commodity");
            }
            if (price.compareTo(new BigDecimal(0)) < 0) {
                throw new Exception("Illegal Price");
            }
            LitemallQuoteCommodity commodity = new LitemallQuoteCommodity();
            commodity.setCommodityId(commodityId);
            commodity.setPid(pid);
            commodity.setPrice(price);
            quoteCommodityMapper.insertSelective(commodity);
        }
    }
}
